﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services;

namespace Muel.TypeScriptFacade.Core
{
    public enum TypeScriptServiceProvider
    {
        AspNetWebService,
        WcfWebService
    }

    public class TypeScriptService
    {
        private Type serviceType;
        private TypeScriptServiceManager manager;
        private TypeScriptServiceUrlHint hint;

        public TypeScriptService(TypeScriptServiceManager manager, Type serviceType)
            : this(manager, serviceType, null) { }

        public TypeScriptService(TypeScriptServiceManager manager, Type serviceType, TypeScriptServiceUrlHint serviceUrlHint)
        {
            this.manager = manager;
            this.serviceType = serviceType;
            this.hint = serviceUrlHint;
            this.Name = serviceType.Name;
        }

        private bool initialised = false;
        internal void Initialise()
        {
            try
            {
                if (!initialised)
                {
                    methods = serviceType
                        .GetMethods()
                        .Where(method => 
                            method.HasAttributeOfType<OperationContractAttribute>(true) || 
                            method.HasAttributeOfType<WebMethodAttribute>())
                        .Select(method => new TypeScriptServiceMethod(manager, this, method))
                        .ToArray();
                }
            }
            finally
            {
                initialised = true;
            }
        }

        private TypeScriptServiceMethod[] methods = null;
        public TypeScriptServiceMethod[] Methods
        {
            get
            {
                Initialise();
                return methods;
            }
        }
        
        public string Name { get; private set; }
        
        public override string ToString()
        {
            return this.Name;
        }

        private string serviceUrl = string.Empty;
        public string ServiceUrl
        {
            get
            {
                if (string.IsNullOrEmpty(serviceUrl))
                {
                    if (this.hint != null)
                    {
                        serviceUrl = this.hint.ServiceUrl;
                    }
                    else
                    {
                         /* if there's no URL hint (probably because this manager instance has been loaded
                          * directly from an assembly via the command line, rather than being loaded from 
                          * WSDL or from the Visual Studio project), then make our best guess based on the settings
                          */
                        string extension;
                        switch (manager.Settings.ServiceProvider)
                        {
                            case Configuration.ServiceProviderEnumeration.AspNetWebService:
                                extension = "asmx";
                                break;
                            case  Configuration.ServiceProviderEnumeration.WcfWebService:
                            default:
                                extension = "svc";
                                break;
                        }

                        serviceUrl = string.Format("{0}/{1}.{2}",
                            manager.Settings.DefaultDomainRelativeServiceUrl.TrimEnd('/'),
                            this.Name,
                            extension);
                    }
                }
                return serviceUrl;
            }
        }

        #region Output to TypeScript

        private string serviceFormat = @"
export class {0} {{
    static ServiceUrl: string = ""{1}"";
{2}
}};";

        internal string ToTypeScript()
        {
            return string.Format(serviceFormat,
                Name,
                ServiceUrl,
                string.Join(
                    Environment.NewLine,
                    this.Methods.Select(method => method.ToTypeScript())));
        }

        #endregion

    }
}
